package com.bay1ts.service.impl;

import java.util.Date;
import java.util.Random;

import com.bay1ts.dao.UsersMapper;
import com.bay1ts.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bay1ts.service.UserService;
import com.bay1ts.utils.Encode;
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
	@Autowired
	private AuthenticationManager authenticationManager;
	@Autowired
	private PasswordEncoder passwordEncoder;
	@Autowired
	private SaltSource saltSource;
	@Autowired
	private UsersMapper usersMapper;
	
	public String getUsernameByEmail(String email){
		return(usersMapper.getUserNameByEmail(email));
	}

	public void insert(Users user) {
		String encodedPassword=passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(user));
		// TODO Auto-generated method stub
		user.setPassword(encodedPassword);
		usersMapper.insert(user);
		usersMapper.insertGroup(user);
		//在一个<insert>标签里面插入两个表的数据，我怕不行，但是在这个场景上应用事务我觉着最合适不过了。所以
		//不如在service层做一个封装，在dao层中分两步插入，就得了
	}
	//把token，时间放进去后还要删掉呢，删掉这个过程发生在密码重置成功了。这里不是事务的应用场景，因为还可以没有点这个链接呢，就不需要删除了。
	public void forgetPassword(String email){
		String token=null;
		try {
			token=Encode.md5_encode(email+new Date().getTime());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			token=new Random(new Date().getTime()).toString();
		}
		usersMapper.updateReset_pw_Token_Time(email, token, new Date());
		
	}

	/** 
	 * @return 
	 * 3 --错误(伪造)的链接
	 * 2 --失效(过期)的链接
	 * 1 --链接验证通过
	 */
	public int confirm(String code){
		//7200==2*60*60 用立即数，不用计算了。
		//生成的链接的有效期
		final int validtime=7200; 
		//初级阶段，只验证token是否正确，不验证是否超时。
		//验证正确的思路：1数据库中首先要存在这个token。
		//2防止类似撞库的攻击手段，随机生成token ？？存疑   解决方案：在发送的链接上附上邮箱  存在token，存在邮箱，邮箱token对应，才能更改。
		//但是是否有这种风险呢？应该是没有，，，在resetpassword末端，记着把token清除就行了。可能考虑的不全面。这样就够安全了
		//为了更友好的显示错误原因，连接是否过期的判断在链接存在的判断之后。但是这样的话，还是不能区分是因为链接错误，还是因为链接过期。所以改一下接口的返回值，改为int
		if(usersMapper.existToken(code)){
			//链接正确的业务逻辑
			//还要时间正确		
			Date currentDate=new Date();
			Date createDate= usersMapper.getDateByToken(code);
			//表示生成链接到现在的时间差的秒数形式
			long diff=(currentDate.getTime()-createDate.getTime())/1000L;
			if(diff>validtime){
				return 2;
			}else{
				return 1;
			}
		}else{
			//链接伪造的业务逻辑
			return 3;
		}
	}
	public void reset(String password,String email,UserDetails user){
		String encodedPassword=passwordEncoder.encodePassword(password, saltSource.getSalt(user));
		usersMapper.updatePasswordByEmail(email, encodedPassword);
		//更新完了该把token删掉，下面准备加重置密码成功后的清理操作。
		usersMapper.cleanupAfterSuccess(email);
	}

	public void dynamicLogin(String phonenumber) {
		int random=(int)((Math.random() * 9 + 1) * 100000);
		usersMapper.updateDynamic_Login_Code_Time(phonenumber,random,new Date());
	}

	public int confirmDynamicCode(int code,String phonenumber) {
		//立即数600 单位 s 表示10分钟
		final int validtime = 600;
		if(usersMapper.existCode(code)){
			//链接正确的业务逻辑
			//还要时间正确
			Date currentDate=new Date();
			Date createDate= usersMapper.getDateByCode(code);
			//表示生成链接到现在的时间差的秒数形式
			long diff=(currentDate.getTime()-createDate.getTime())/1000L;
			if(diff>validtime){
				//动态密码超时的逻辑
				return 2;
			}else{
				return 1;
			}
		}else{
			//动态密码伪造的逻辑
			return 3;
		}
	}
	public void test(String u,String p){
		String username=u;
		String password=p;
		Authentication authentication=new UsernamePasswordAuthenticationToken(username,password);
		authenticationManager.authenticate(authentication);
	}


}
